package xyz.xtt.pay.service.order;

import static xyz.xtt.common.asset.AssertUtils.isFalse;
import static xyz.xtt.common.asset.AssertUtils.isNull;
import static xyz.xtt.common.asset.AssertUtils.isTrue;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.asset.api.enums.AssetTypeEnum;
import xyz.xtt.asset.api.enums.BizTypeEnum;
import xyz.xtt.asset.api.enums.GoodsTypeEnum;
import xyz.xtt.asset.api.enums.OwnerTypeEnum;
import xyz.xtt.asset.api.enums.ReferProtocolEnum;
import xyz.xtt.asset.api.enums.SecondEnum;
import xyz.xtt.asset.api.enums.SellPatternEnum;
import xyz.xtt.asset.client.request.MakeTransactionRequest;
import xyz.xtt.asset.client.response.AssetAccountResponse;
import xyz.xtt.asset.client.response.AssetAllInfoResponse;
import xyz.xtt.asset.client.response.AssetExtInfoResponse;
import xyz.xtt.asset.client.response.AssetInfoResponse;
import xyz.xtt.asset.client.response.AssetStaticResponse;
import xyz.xtt.asset.client.response.AssetTransactionResponse;
import xyz.xtt.equity.api.enums.BenefitEnum;
import xyz.xtt.equity.client.request.TblUserBenefitDto;
import xyz.xtt.pay.api.enums.PayOrderBusinessTypeEnum;
import xyz.xtt.pay.api.enums.PayOrderStatusEnum;
import xyz.xtt.pay.client.request.MakeOrderRequest;
import xyz.xtt.pay.constants.ErrorMessage;
import xyz.xtt.pay.entity.TblBusinessOrder;
import xyz.xtt.pay.exception.ChainException;
import xyz.xtt.pay.service.BusinessOrderOperator;
import xyz.xtt.pay.service.IInnerService;
import xyz.xtt.pay.service.INftOrderService;
import xyz.xtt.pay.service.ITblBusinessOrderService;

/**
 * NFT购买相关各子业务订单操作（包含：致敬传奇盲盒、玫瑰盲盒、平台1155协议NFT购买、c2c资产购买）
 * 
 * @author dale
 * @date 2025/3/18
 **/
@Service
@Slf4j
public class NftPurchaseBusinessOrderOperator implements BusinessOrderOperator {
	@Autowired
	private INftOrderService nftOrderService;
	@Autowired
	private ITblBusinessOrderService iTblBusinessOrderService;
	@Autowired
	private IInnerService iInnerService;

	/**
	 * 是否支持该类型的订单
	 *
	 * @param type
	 * @return
	 */
	@Override
	public boolean canOperateType(PayOrderBusinessTypeEnum type) {
		return Objects.equals(type, PayOrderBusinessTypeEnum.NFT_PURCHASE);
	}

	/**
	 * 创建订单
	 *
	 * @param uid              用户ID
	 * @param makeOrderRequest 创建订单请求
	 * @return 订单
	 */
	@Override
	public TblBusinessOrder makeOrder(String uid, MakeOrderRequest makeOrderRequest) {
		long assetAccountId = Long.parseLong(makeOrderRequest.getAssetAccountId());
		int purchaseAmount = makeOrderRequest.getPurchaseAmount();
		long buyerId = Long.parseLong(uid);
		AssetAccountResponse assetAccount = iInnerService.accountInfoWithId(assetAccountId);
		isNull(assetAccount, ErrorMessage.ASSET_ACCOUNT_NOT_EXIST);
		isFalse(assetAccount.getAmount().intValue() >= purchaseAmount, ErrorMessage.STOCK_NOT_ENOUGH);
		isTrue(Objects.equals(buyerId, assetAccount.getOwnerId()), ErrorMessage.CAN_NOT_BUY_SELF);
		long sellerId = assetAccount.getOwnerId();
		AssetAllInfoResponse allInfoAsset = iInnerService.allInfoAssetId(assetAccount.getAssetId());
		isNull(allInfoAsset, ErrorMessage.ASSET_NOT_EXIST);
		AssetInfoResponse asset = allInfoAsset.getAsset();
		isNull(asset, ErrorMessage.ASSET_NOT_EXIST);
		isFalse(Objects.equals(BizTypeEnum.NFT.dbType(), asset.getBizType()), ErrorMessage.ASSET_STATUS_EX);
//        isFalse(Objects.equals(asset.getSellable(),1),ErrorMessage.ASSET_NOT_SELLABLE);
		isFalse(Objects.equals(assetAccount.getSellPattern(), SellPatternEnum.BUY_NOW_PRICE.code()), ErrorMessage.ASSET_STATUS_EX);
		AssetExtInfoResponse assetExt = allInfoAsset.getAssetExt();
		PayOrderBusinessTypeEnum businessTypeEnum = calculateBusinessType(asset, assetExt);
		isTrue(Objects.equals(businessTypeEnum, PayOrderBusinessTypeEnum.ROSE_MINT) && purchaseAmount > 1, ErrorMessage.INVALID_QUANTITY);
		if (Objects.equals(businessTypeEnum, PayOrderBusinessTypeEnum.C_TO_C)) {
			// 个人售卖需要进行公示期、预售期校验
			isTrue(assetExt.getPublicityPeriodStart() == null || assetExt.getPublicityPeriodEnd() == null || assetExt.getPublicityPeriodStart() == 0L
					|| assetExt.getPublicityPeriodEnd() == 0L
					|| assetExt.getPublicityPeriodEnd() > System.currentTimeMillis(), ErrorMessage.ASSET_NOT_PUBLICIZED);
			isFalse(checkAssetBeginSale(assetExt), ErrorMessage.ASSET_NOT_START_SALE);
		}
		// 预售购买权限校验
		boolean isPreSale = assetExt.getPreSellStartDatetime() != null && assetExt.getSellStartDatetime() != null
				&& assetExt.getPreSellStartDatetime() < assetExt.getSellStartDatetime() && assetExt.getPreSellStartDatetime() <= System.currentTimeMillis()
				&& assetExt.getSellStartDatetime() > System.currentTimeMillis();
		if (isPreSale) {
			Boolean hasGift365 = iInnerService.hasGift365(buyerId);
			if (!hasGift365 && !hasPrePurchaseBenefit(buyerId)) {
				throw new ChainException(ErrorMessage.NEED_PRE_PURCHASE_BENEFIT);
			}
		}
		AssetStaticResponse assetStaticResource = allInfoAsset.getAssetStatic();
		isNull(assetStaticResource, ErrorMessage.ASSET_STATUS_EX);
		GoodsTypeEnum goodsTypeEnum = GoodsTypeEnum.valueOf(businessTypeEnum.name());
		String goodsId = String.valueOf(asset.getId());
		// 检查是否有待支付的订单
		TblBusinessOrder unPayOrder = iTblBusinessOrderService.getUnPayBusinessOrder(buyerId, goodsTypeEnum.getCode(), goodsId);
		if (unPayOrder != null) {
			return unPayOrder;
		}

		BigDecimal unitPrice = assetAccount.getPrice();
		// 测试用户重置单价
		unitPrice = nftOrderService.testUserResetPrice(buyerId, unitPrice);
		TblBusinessOrder businessOrder = buildBusinessOrder(asset, assetStaticResource, unitPrice, sellerId, buyerId, businessTypeEnum, purchaseAmount, unitPrice);

		// 库存预占
		MakeTransactionRequest makeTransactionRequest = MakeTransactionRequest
				.builder()
				.from(sellerId)
				.to(buyerId)
				.num(purchaseAmount)
				.assetId(assetAccount.getAssetId())
				.price(unitPrice.toPlainString())
				.expireTimeWithLevel(0)
				.orderType(businessTypeEnum.name())
				.fees("0")
				.build();
		if (StringUtils.isNotBlank(makeOrderRequest.getAssetNoId())) {
			makeTransactionRequest.setAssetNoId(Long.valueOf(makeOrderRequest.getAssetNoId()));
		}
		makeTransactionRequest.setOrderPrice(businessOrder.getTotalPrice());
		makeTransactionRequest.setBizType("nft");
		AssetTransactionResponse transaction = iInnerService.makeTransaction(makeTransactionRequest);
		isNull(transaction, ErrorMessage.ORDER_CREATE_FAILED, () -> log
				.info("uid:{} makeOrderRequest:{} transaction result is null", buyerId, JSONUtil.toJsonStr(makeTransactionRequest)));
		businessOrder.setBusinessRefId(String.valueOf(transaction.getOrderId()));
		isFalse(iTblBusinessOrderService
				.save(businessOrder), ErrorMessage.ORDER_CREATE_FAILED, () -> log.error("save order failed. order:{}", JSONUtil.toJsonStr(businessOrder)));
		return businessOrder;
	}

	private TblBusinessOrder buildBusinessOrder(AssetInfoResponse asset, AssetStaticResponse assetStaticResource, BigDecimal unitPrice, long sellerId,
			long buyerId, PayOrderBusinessTypeEnum businessTypeEnum, int purchaseAmount, BigDecimal price) {
		TblBusinessOrder order = new TblBusinessOrder();
		order.setOrderId(IdUtil.getSnowflakeNextId());
		order.setGoodsId(String.valueOf(asset.getId()));
		order.setGoodsType(GoodsTypeEnum.valueOf(businessTypeEnum.name()).getCode());
		order.setGoodsName(asset.getAssetName());
		order.setGoodsImage(assetStaticResource.getLogoUri());
		order.setSellerId(sellerId);
		order.setAppUserId(buyerId);
		order.setPurchaseNum(purchaseAmount);
		order.setOriginPrice(unitPrice.setScale(2, RoundingMode.HALF_UP));
		order.setRealPrice(order.getOriginPrice());
		order.setTransportPrice(BigDecimal.ZERO);
		order.setDiscountAmount(BigDecimal.ZERO);
		order.setTotalPrice(calculateOrderTotalPrice(order));
		order.setPayAmount(order.getTotalPrice());
		order.setOrderStatus(PayOrderStatusEnum.UN_PAY.getCode());
		LocalDateTime now = LocalDateTime.now();
		order.setOrderTime(now);
		order.setCreateTime(now);
		order.setUpdateTime(now);
		return order;
	}

	/**
	 * 判断藏品类型
	 * 
	 * @param asset
	 * @param assetExt
	 * @return
	 */
	private PayOrderBusinessTypeEnum calculateBusinessType(AssetInfoResponse asset, AssetExtInfoResponse assetExt) {
		if (Objects.equals(asset.getSecondType(), SecondEnum.BLIND.getCode())) {
			// 致敬传奇盲盒
			return PayOrderBusinessTypeEnum.NORMAL;
		} else if (Objects.equals(asset.getOwnerType(), OwnerTypeEnum.USER.code()) || Objects.equals(asset.getOwnerType(), OwnerTypeEnum.AGENT.code())) {
			// c2c资产购买
			return PayOrderBusinessTypeEnum.C_TO_C;
		} else if (Objects.equals(asset.getSecondType(), SecondEnum.ROSE.getCode())) {
			// 玫瑰盲盒
			return PayOrderBusinessTypeEnum.ROSE_MINT;
		} else if (Objects.equals(asset.getFirstType(), AssetTypeEnum.BLIND_BOX.code())) {
			// nft盲盒
			return PayOrderBusinessTypeEnum.NFT_BLIND_BOX;
		} else if (Objects.equals(assetExt.getReferProtocol(), ReferProtocolEnum.ERC_1155.getDescription())) {
			// 平台1155协议NFT购买
			return PayOrderBusinessTypeEnum.BUY_ASSET_1155;
		} else {
			throw new ChainException(ErrorMessage.ASSET_STATUS_EX);
		}
	}

	/**
	 * 检查藏品是否开售
	 * 
	 * @param assetExt
	 * @return
	 */
	private boolean checkAssetBeginSale(AssetExtInfoResponse assetExt) {
		if (assetExt.getPreSellStartDatetime() == null || Objects.equals(assetExt.getPreSellStartDatetime(), 0L)) {
			// 未发布过
			return false;
		}
		return System.currentTimeMillis() > assetExt.getPreSellStartDatetime();
	}

	/**
	 * 判断用户是否拥有预先购买权
	 *
	 * @param appUserId
	 * @return
	 */
	private boolean hasPrePurchaseBenefit(Long appUserId) {
		TblUserBenefitDto latestUserBenefit = iInnerService.getLatestUserBenefit(String.valueOf(appUserId), BenefitEnum.PRIORITY_BUY.getCode());
		return latestUserBenefit != null && latestUserBenefit.getExpireAt().isAfter(LocalDateTime.now());
	}
}
